package cn.edu.sjtu.stap.sootbranchinstr.postprocess;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import cn.edu.sjtu.stap.sootbranchinstr.BranchRecorder;
import cn.edu.sjtu.stap.sootbranchinstr.template.IfTemplate;
import cn.edu.sjtu.stap.sootbranchinstr.template.PolyTemplate;
import cn.edu.sjtu.stap.sootbranchinstr.template.SwitchTarget;
import cn.edu.sjtu.stap.sootbranchinstr.template.SwitchTemplate;

public class PostProcessor {
	public static String ifRecordFileName;
	public static String switchRecordFileName;
	public static String polyRecordFileName;
	
	public static String ifTemplateFileName;
	public static String switchTemplateFileName;
	public static String polyTemplateFileName;
	
	public static List<IfTemplateWithData> ifDataList = new ArrayList<IfTemplateWithData>();
	public static List<SwitchTemplateWithData> swDataList = new ArrayList<SwitchTemplateWithData>();
	public static List<PolyTemplateWithData> polyDataList = new ArrayList<PolyTemplateWithData>();
	
	public static void postProcessIf(){
		try{
			BufferedReader ifReader = new BufferedReader(new FileReader(ifTemplateFileName));
			String tempLine = ifReader.readLine();
			while(tempLine != null){
				String[] ifTempSegs = tempLine.split(BranchRecorder.DATA_SEPARATOR);
				IfTemplate it = new IfTemplate();
				it.setKey(ifTempSegs[0] + BranchRecorder.DATA_SEPARATOR + ifTempSegs[1]);
				it.setTakenTarget(ifTempSegs[2]);
				
				IfTemplateWithData ifData = new IfTemplateWithData();
				ifData.setIt(it);
				ifDataList.add(ifData);
				
				tempLine = ifReader.readLine();
			}
			ifReader.close();
			
			BufferedReader ifDataReader = new BufferedReader(new FileReader(ifRecordFileName));
			String dataLine = ifDataReader.readLine();
			while(dataLine != null){
				String[] dataSegs = dataLine.split(BranchRecorder.DATA_SEPARATOR);
				String dataKey = dataSegs[0] + BranchRecorder.DATA_SEPARATOR + dataSegs[1];
				int takenCount = 0, untakenCount = 0;
				for(int i = 2; i < dataSegs.length; i++){
					if(dataSegs[i] != null){
						if(dataSegs[i].equals("taken")){
							takenCount = Integer.valueOf(dataSegs[i+1]);
						}else if(dataSegs[i].equals("untaken")){
							untakenCount = Integer.valueOf(dataSegs[i+1]);
						}
					}
				}
				
				for(IfTemplateWithData ifData : ifDataList){
					IfTemplate it = ifData.getIt();
					if(it.getKey().equals(dataKey)){
						ifData.setTakenCount(takenCount);
						ifData.setUntakenCount(untakenCount);
						break;
					}
				}
				
				dataLine = ifDataReader.readLine();
			}
			ifDataReader.close();
		}catch(IOException ex){
			ex.printStackTrace();
		}
	}
	
	public static void postProcessSwitch(){
		try{
			BufferedReader stReader = new BufferedReader(new FileReader(switchTemplateFileName));
			String stLine = stReader.readLine();
			while(stLine != null){
				String[] tempSegs = stLine.split(BranchRecorder.DATA_SEPARATOR);
				SwitchTemplate st = new SwitchTemplate();
				st.setKey(tempSegs[0] + BranchRecorder.DATA_SEPARATOR + tempSegs[1]);
				List<SwitchTarget> tList = new ArrayList<SwitchTarget>();
				for(int i = 2; i < tempSegs.length; i++){
					SwitchTarget sTarget = new SwitchTarget();
					sTarget.setTargetIndex(tempSegs[i]);
					sTarget.setTargetLine(tempSegs[++i]);
					tList.add(sTarget);
				}
				st.setTargets(tList);
				
				SwitchTemplateWithData swData = new SwitchTemplateWithData();
				swData.setSt(st);
				swDataList.add(swData);
				
				stLine = stReader.readLine();
			}
			stReader.close();
			
			BufferedReader swDataReader = new BufferedReader(new FileReader(switchRecordFileName));
			String swDataLine = swDataReader.readLine();
			while(swDataLine != null){
				String[] dataSegs = swDataLine.split(BranchRecorder.DATA_SEPARATOR);
				String dataKey = dataSegs[0] + BranchRecorder.DATA_SEPARATOR + dataSegs[1];
				
				for(SwitchTemplateWithData sd : swDataList){
					if(sd.getSt().getKey().equals(dataKey)){
						int defaultCount = 0;
						List<Integer> tcList = new ArrayList<Integer>();
						for(int c = 0; c < sd.getSt().getTargets().size(); c++){
							tcList.add(null);
						}
						
						for(int i = 2; i < dataSegs.length; i++){
							String targetKey = dataSegs[i];
							String targetCount = dataSegs[++i];
							
							boolean isDefault = true;
							List<SwitchTarget> tList = sd.getSt().getTargets();
							for(int ti = 0; ti < tList.size(); ti++){
								// targetKey will never be "default"
								if(tList.get(ti).getTargetIndex().equals(targetKey)){
									tcList.set(ti, new Integer(targetCount));
									isDefault = false;
									break;
								}
							}
							if(isDefault){
								defaultCount += Integer.valueOf(targetCount);
							}
						}
						
						tcList.set(sd.getSt().getTargets().size() - 1, new Integer(defaultCount)); // set the count of default case in the last slot
						sd.setTargetCounts(tcList);
						break;
					}
				}
				
				swDataLine = swDataReader.readLine();
			}
			swDataReader.close();
		}catch(IOException ex){
			ex.printStackTrace();
		}
	}
	
	public static void postProcessPoly(){
		try{
			BufferedReader ptReader = new BufferedReader(new FileReader(polyTemplateFileName));
			String ptLine = ptReader.readLine();
			while(ptLine != null){
				String[] tempSegs = ptLine.split(BranchRecorder.DATA_SEPARATOR);
				PolyTemplate pt = new PolyTemplate();
				pt.setKey(tempSegs[0] + BranchRecorder.DATA_SEPARATOR 
						  + tempSegs[1] + BranchRecorder.DATA_SEPARATOR
						  + tempSegs[2]);
				pt.setCallType(tempSegs[3]);
				
				List<String> tList = new ArrayList<String>();
				pt.setTargets(tList);
				for(int i = 4; i < tempSegs.length; i++){
					tList.add(tempSegs[i]);
				}
				
				PolyTemplateWithData ptData = new PolyTemplateWithData();
				ptData.setPt(pt);
				
				polyDataList.add(ptData);
				ptLine = ptReader.readLine();
			}
			ptReader.close();
			
			BufferedReader ptDataReader = new BufferedReader(new FileReader(polyRecordFileName));
			String pdLine = ptDataReader.readLine();
			while(pdLine != null){
				String[] pdSegs = pdLine.split(BranchRecorder.DATA_SEPARATOR);
				String dataKey = pdSegs[0] + BranchRecorder.DATA_SEPARATOR +
				                 pdSegs[1] + BranchRecorder.DATA_SEPARATOR +
				                 pdSegs[2];
				
				for(PolyTemplateWithData pd : polyDataList){
					if(pd.getPt().getKey().equals(dataKey)){
						List<Integer> tcList = new ArrayList<Integer>();
						for(int i = 0; i < pd.getPt().getTargets().size(); i++){
							tcList.add(null);
						}
						
						for(int i = 3; i < pdSegs.length; i++){
							String tKey = pdSegs[i];
							String tData = pdSegs[++i];
							
							List<String> polyTargets = pd.getPt().getTargets();
							for(int ti = 0; ti < polyTargets.size(); ti++){
								String targetSig = polyTargets.get(ti);
								String targetClassName = targetSig.substring(targetSig.indexOf("<") + 1, targetSig.indexOf(":"));
								if(targetClassName.equals(tKey)){
									tcList.set(ti, new Integer(tData));
									break;
								}
							}
						}
						
						pd.setTargetCounts(tcList);
						break;
					}
				}
				pdLine = ptDataReader.readLine();
			}
			ptDataReader.close();
		}catch(IOException ex){
			ex.printStackTrace();
		}
	}
	
	public static void prettyPrint(boolean printIf, boolean printSwitch, boolean printPoly){
		if(printIf){
			StringBuilder ifStr = new StringBuilder("\n*************************DATA OF IF BRANCHES:\n");
			for(IfTemplateWithData itwd : ifDataList){
				if( !(itwd.getTakenCount() == 0 && itwd.getUntakenCount() == 0) ){
					ifStr.append(itwd.getIt().getKey());
					ifStr.append("\n       taken: ");  // there are seven spaces.
					ifStr.append(itwd.getTakenCount());
					ifStr.append("\n       untaken: ");
					ifStr.append(itwd.getUntakenCount());
					ifStr.append("\n");
				}
			}
			
			System.out.println(ifStr.toString());
		}
		
		if(printSwitch){
			StringBuilder swStr = new StringBuilder("\n-----------------------DATA OF SWITCH BRANCHES:\n");
			for(SwitchTemplateWithData stwd : swDataList){
				if(stwd.getTargetCounts() != null){
					swStr.append(stwd.getSt().getKey());
					
					List<TargetAndCount> tacList = new ArrayList<TargetAndCount>();
					for(int i = 0; i < stwd.getSt().getTargets().size(); i++){
						TargetAndCount tempAC = new TargetAndCount();
						tempAC.setKey(stwd.getSt().getTargets().get(i).getTargetIndex());
						Integer tempC = stwd.getTargetCounts().get(i);
						if(tempC != null){
							tempAC.setCount(tempC.intValue());
						}else{
							tempAC.setCount(0);
						}
						tacList.add(tempAC);
					}
					Collections.sort(tacList);
					
					for(int i = tacList.size() - 1; i >= 0; i--){
						swStr.append("\n       ");
						swStr.append(tacList.get(i).getKey());
						swStr.append(": ");
						swStr.append(tacList.get(i).getCount());
					}
					
					swStr.append("\n");
				}
			}
			
			System.out.println(swStr.toString());
		}
		
		if(printPoly){
			StringBuilder polyStr = new StringBuilder("\n$$$$$$$$$$$$$$$$$$$$$$$$$$$$$DATA OF POLY BRANCHES:\n");
			for(PolyTemplateWithData ptwd : polyDataList){
				if(ptwd.getTargetCounts() != null){
					polyStr.append(ptwd.getPt().getKey());
					
					List<TargetAndCount> tacList = new ArrayList<TargetAndCount>();
					for(int i = 0; i < ptwd.getPt().getTargets().size(); i++){
						TargetAndCount tempAC = new TargetAndCount();
						tempAC.setKey(ptwd.getPt().getTargets().get(i));
						Integer tempC = ptwd.getTargetCounts().get(i);
						if(tempC != null){
							tempAC.setCount(tempC.intValue());
						}else{
							tempAC.setCount(0);
						}
						tacList.add(tempAC);
					}
					Collections.sort(tacList);
					
					for(int i = tacList.size() - 1; i >= 0; i--){
						polyStr.append("\n       ");
						polyStr.append(tacList.get(i).getKey());
						polyStr.append(": ");
						polyStr.append(tacList.get(i).getCount());
					}
					
					polyStr.append("\n");
				}
			}
			
			System.out.println(polyStr.toString());
		}
	}
	
	public static void main(String[] args){
/*		ifRecordFileName = "G:/29_DaCapo/for_branch_prediction_20100312/if_record.txt";
		ifTemplateFileName = "G:/Develop/workspace3.5.1_callchainfreq/SootBranchInstru/if_temp.txt";
		postProcessIf();
		
		switchRecordFileName = "G:/29_DaCapo/for_branch_prediction_20100312/switch_record.txt";
		switchTemplateFileName = "G:/Develop/workspace3.5.1_callchainfreq/SootBranchInstru/sw_temp.txt";
		postProcessSwitch();

		polyRecordFileName = "G:/29_DaCapo/for_branch_prediction_20100312/poly_record.txt";
		polyTemplateFileName = "G:/Develop/workspace3.5.1_callchainfreq/SootBranchInstru/poly_temp.txt";
		postProcessPoly();*/
		
//		polyRecordFileName = "G:/Develop/2010-03-19/luindex/poly_record.txt";
//		polyTemplateFileName = "G:/Develop/2010-03-19/luindex/poly_temp.txt";
//		postProcessPoly();
		
		switchRecordFileName = "G:/Develop/2010-03-19/pmd/switch_record.txt";
		switchTemplateFileName = "G:/Develop/2010-03-19/pmd/sw_temp.txt";
		postProcessSwitch();
		
		prettyPrint(false, true, false);
	}
}
